package com.utils.load
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	
	/**
	 * 全局可使用的加载管理器 主要目的将种子变成实体
	 * @author Administrator
	 */	
	
	public class LoadManager
	{
		public static const LOAD_OVER:String = "LOAD_OVER";
		
		public static const LOAD_PROCESS:String = "LOAD_PROCESS"; //加载进度事件
		
		private static var loaderList:Vector.<Loader> = new Vector.<Loader>();
		
		private static var loadDispatcher:EventDispatcher = 
			new EventDispatcher();
		
//		private static var loader:Loader = new Loader(); 
		
		//加载器只有一个 同一时间只能加载一个 
		//如需要重复加载 先将种子全部存入数组 等当前加载进度完成再加载下一个种子即可
		
//		private static var isLoading:Boolean = false; //纪录当前加载状态是否在加载
		
		private static var infoList:Array = []; //暂存未加载的种子
		
		private static var sourceCount:int; //纪录当前总的加载任务数
		
		/**
		 * 让外部侦听此事件 将事件的回调函数传入
		 * @param func 外部传入的回调函数
		 */	
		public static function addLoadProcess(func:Function):void{
			loadDispatcher.addEventListener(LoadManager.LOAD_PROCESS , func);
		}
		
		/**
		 * 让外部停止侦听此事件 将事件的回调函数传入
		 * @param func 外部传入的回调函数
		 */	
		public static function removeLoadProcess(func:Function):void{
			loadDispatcher.removeEventListener(LoadManager.LOAD_PROCESS , func);
		}
		
		/**
		 * 让外部侦听此事件 将事件的回调函数传入
		 * @param func 外部传入的回调函数
		 */		
		public static function addLoadOver(func:Function):void{
			loadDispatcher.addEventListener(LoadManager.LOAD_OVER , func);
		}
		
		/**
		 * 让外部停止侦听此事件 将事件的回调函数传入
		 * @param func 外部传入的回调函数
		 */	
		public static function removeLoadOver(func:Function):void{
			loadDispatcher.removeEventListener(LoadManager.LOAD_OVER , func);
		}
		
		/**
		 *     		{	url
		 *  loadVo   	loadFunction
		 * 				args   }
		 * 
		 * 加载目标地址 处理加载完成后的事情
		 * @param url 种子地址
		 * @param loadFunction 加载完了目标需要执行的函数
		 * @param args 加载完成目标函数可选参数列表
		 */		
		public static function loadSource(url:String,
			loadFunction:Function = null,...args):void{
			
			var loadObj:LoadVo = new LoadVo(); //通过创建自定义Object绑定两个数据
			loadObj.url = url;
			loadObj.loadFunction = loadFunction;
			loadObj.args = args;
			
			infoList.push(loadObj); //种子先排队
			
			sourceCount = infoList.length;
			
			//result = loadFunction;
//			loadStart(); //因为有一张已经从数组里切除了 所以纪录总长度应该执行此函数之前
		}
		
		/**
		 * 对目标地址进行加载 loader.load(url)  loadComplete
		 * @param url
		 */		
		private static var loaderDic:Dictionary = new Dictionary(true);
		public static function loadStart():void{
//			if(isLoading == true){
//				return; //判断是否已经有线程在加载
//			}
			
			var loadObj:LoadVo = infoList.shift();
			//下面取出最新数据
//			resultUrl = loadObj.url; //存储当前种子地址
//			
//			result = loadObj.loadFunction; //存储当前种子对应的回调函数
//			
//			resultContain = loadObj.contain; //存储当前种子对应的容器
			
			if(ResourceBox.cotainKey(loadObj.url)){ //如果已经在内存里面找到了 就不加载
				//将已存在的位图信息复制一份位图出来 给回调函数调用
				trace("从素材池里面取" + loadObj.url);
				var bitmapData:BitmapData = ResourceBox.getResource(loadObj.url);
				var bitmap:Bitmap = new Bitmap(bitmapData); //将源图像序列给新的位图去显示
				loadOver(loadObj,bitmap);
				return;
			}
			
			trace("开始加载了" + loadObj.url);
			var loader:Loader = createLoader();
//			if(loadObj.isSheet)loadSheetList.push(loader);
			loaderDic[loader] = loadObj;
			loader.load(new URLRequest(loadObj.url));
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE,loadComplete);
			loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR,ioHandler);
//			isLoading = true; //一旦此线程种子开始加载 标记正在加载
		}
		
		/**
		 * 生产加载器的工厂方法
		 * @return 
		 */		
		private static function createLoader():Loader{
			if(loaderList.length)var loader:Loader = loaderList.pop();
			else loader = new Loader();
			return loader;
		}
		
		/**
		 * 只能通过loader发出事件 因为wait是静态方法(类调用的方法) 
		 * 在静态方法中不存在this 因为this是通过此类创造的实例对象
		 * 所以无法在静态方法中调用通过this的实例方法dispatchEvent
		 * 而loader已经是实例对象 且继承EventDispatcher事件发送者 所以是发送的合适人选
		 */
		private static function wait():void
		{
//			loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loadComplete);
//			loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,ioHandler);
//			loader.unload(); //断开和片子的联系
			
			if(loadDispatcher.hasEventListener(LoadManager.LOAD_OVER)){
				loadDispatcher.dispatchEvent(new Event(LoadManager.LOAD_OVER)); //发出加载完成事件
			}
		}
		
		/**
		 * 当图片无法加载的时候也要驱动加载下一张图片
		 * @param e
		 */		
		private static function ioHandler(e:IOErrorEvent):void
		{
			trace(e); //加载错误的时候直接跳过当前种子 加载下一个种子
			var loader:Loader = (e.target as LoaderInfo).loader;
			dispose(loader);
			loaderList.push(loader);
			var loadObj:LoadVo = loaderDic[loader];
//			var loadVo:LoadVo = loaderDic[loader];
//			isLoading = false; //当此线程种子加载完成 标记可以继续加载
			
			loadOver(loadObj);
		}
		
		/**
		 * loadComplete方法执行调用外部传入的函数
		 * loader.content获取实体(片) 当做参数执行回调
		 * 加载完成后还要继续加载下一个种子
		 */		
		private static function loadComplete(e:Event):void{
			var loader:Loader = (e.target as LoaderInfo).loader;
			var bitmap:Bitmap = loader.content as Bitmap;
			var loadObj:LoadVo = loaderDic[loader];
			ResourceBox.setResource(loadObj.url,bitmap.bitmapData); //存入最新的数据
			
			dispose(loader);
			loaderList.push(loader);
			
			loadOver(loadObj,bitmap);
		}
		
		private static function dispose(loader:Loader):void{
			loader.contentLoaderInfo.removeEventListener(Event.COMPLETE,loadComplete);
			loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR,ioHandler);
			loader.unload(); //断开和片子的联系
		}
		
		/**
		 * 加载结束处理当前片子 决定该片子的去留(卖给厂商)
		 * @param bitmap 片子
		 */		
		private static function loadOver(loadObj:LoadVo = null,
										 bitmap:Bitmap = null):void{
			if(loadObj.loadFunction != null){ 
				//如果传入第二个参数才执行 否则报空指针
//				if(loadObj.isSheet){
//					if(bitmap != null)loadObj.loadFunction(bitmap,loadObj.contain,
//						loadObj.row,loadObj.col);
//				}else{
					if(loadObj.args != null){ //如果传入第三个参数
						loadObj.args.unshift(bitmap);
						loadObj.loadFunction.apply(null,loadObj.args);
						//如果第三个参数传入 也将自己作为参数传出
					}else{
						loadObj.loadFunction(bitmap);
					}
//				}
			}
//			isLoading = false; //当此线程种子加载完成 标记可以继续加载
//			loadProcess(); //抛出加载进度事件
//			if(!loadObj.isSheet){
				if(infoList.length > 0)loadStart(); //继续执行下一个加载线程
				else wait();
//			}
		}
		
//		private static var loadSheetList:Vector.<Loader> = 
//			new Vector.<Loader>();
		
//		public static function loadSheet(cotain:Bitmap,fileName:String,
//										 loadFunc:Function = null):void{
////			unLoadSheet(sp);
//			if(ResourceBox.cotainKey(fileName)){
//				cotain.bitmapData = ResourceBox.getResource(fileName);
//				if(loadFunc != null)loadFunc();
//				return;
//			}
//			loadSource(fileName + ".png",loadPreView,cotain,fileName,loadFunc);
//			loadStart();
//		}
////		
//		private static function loadPreView(source:Bitmap,
//					cotain:Bitmap,fileName:String,loadFunc:Function = null):void{
//			if(source == null){
//				ResourceBox.setResource(fileName,null);
//				cotain.bitmapData = null;
//				return;
//			}
//			var scale:int = 10;
//			source.scaleX = source.scaleY = scale;
//			var bd:BitmapData = new BitmapData(source.width,source.height,true,0);
//			bd.draw(source,new Matrix(scale,0,0,scale));
//			cotain.bitmapData = bd;
//			ResourceBox.setResource(fileName,bd);
//			if(loadFunc != null)loadFunc();
////			if(fileName.search('front') >= 0)cotain.
//			var rows:int = Math.ceil(bd.height / GameModel.SHEET_HEIGHT);
//			var cols:int = Math.ceil(bd.width / GameModel.SHEET_WIDTH);
//			for (var i:int = 0; i < rows; i++) 
//			{
//				for (var j:int = 0; j < cols; j++) 
//				{
//					loadSource(fileName + "_" + i + "_" + j + ".png",
//						sheetCallBack,bd,i,j);
//				}
//			}
//			loadStart();
//		}
		
//		private static function sheetCallBack(source:Bitmap,
//								cotain:BitmapData,row:int,col:int):void{
//			var sourceBmd:BitmapData = source.bitmapData;
//			cotain.copyPixels(sourceBmd,sourceBmd.rect,
//				new Point(col * GameModel.SHEET_WIDTH,
//					row * GameModel.SHEET_HEIGHT));
//			if(cotain is Sprite){
//				var sp:Sprite = cotain as Sprite;
//				sp.addChild(source);
//				source.x = col * GameModel.MAP_GRID;
//				source.y = row * GameModel.MAP_GRID;
//			}else{
////				var item:GpuObj2d = new GpuObj2d(source.width,source.height,
////					source.bitmapData,0,0);
//				var gpu:GpuObj2d = cotain as GpuObj2d;
//				var bmd:BitmapData = gpu.bmd;
//				var sourceBmd:BitmapData = source.bitmapData;
////				bmd.fillRect(bmd.rect,0xFF0000FF);
//				bmd.copyPixels(sourceBmd,sourceBmd.rect,
//					new Point(col * GameModel.SHEET_WIDTH,row * GameModel.SHEET_HEIGHT));
////				gpu.setBmd(bmd,0,0);
//				gpu.bmd = bmd;
//				gpu.updateAnimation();
//			}
//		}
		
		/**
		 * 卸载并移除子对象
		 */		
		private static function unLoadSheet(sheetSp:Object):void{
			if(sheetSp is Sprite){
				var sp:Sprite = sheetSp as Sprite;
				while(sp.numChildren){
					sp.removeChildAt(sp.numChildren - 1);
				}
			}/*else{
				var gpu:GpuObj2d = sheetSp as GpuObj2d;
				while(gpu.childs && gpu.childs.length){
					gpu.remove(gpu.childs[0]);
				}
			}*/
//			for (var i:int = 0; i < loadSheetList.length; i++) 
//			{
//				var loader:Loader = loadSheetList.pop();
//				dispose(loader);
//				loaderList.push(loader); //回收
//			}
		}
		
		/*private static function loadProcess():void{
			var pe:ProcessEvent = new ProcessEvent(LoadManager.LOAD_PROCESS);
			pe.rate = (sourceCount - loadList.length) / sourceCount ; //已加载的长度 / 总长度
			loadDispatcher.dispatchEvent(pe);
		}*/
		
	}
}
class LoadVo
{
	public var url:String;
	public var loadFunction:Function;
	public var args:Array;
//	public var isSheet:Boolean; //是否是切片处理
//	public var row:int;
//	public var col:int;
}